package com.ning.ems.service.impl;

import com.ning.ems.dao.AddressDao;
import com.ning.ems.dao.UserDao;
import com.ning.ems.dto.AddressUpdateDto;
import com.ning.ems.entity.Address;
import com.ning.ems.entity.User;
import com.ning.ems.enums.Province;
import com.ning.ems.service.AddressService;
import com.ning.ems.vo.AddressVo;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Ning 242741154@qq.com
 * @date 2020/4/12 1:39
 */
@Service
public class AddressServiceImpl implements AddressService {
    private final UserDao userDao;
    private final AddressDao addressDao;
    private final RedisTemplate<String, Serializable> redisTemplate;

    public AddressServiceImpl(AddressDao addressDao, UserDao userDao, RedisTemplate<String, Serializable> redisTemplate) {
        this.addressDao = addressDao;
        this.userDao = userDao;
        this.redisTemplate = redisTemplate;
    }

    @Override
    @Cacheable(cacheNames = "addr", key = "'owner-'+#owner")
    public List<AddressVo> list(Integer owner) {
        return addressDao
                .list(owner)
                .stream()
                .map(e -> new AddressVo(e.getId(), e.getOwner(), e.getContactNumber(),
                        Province.descOf(e.getProvince()), e.getExactAddr()))
                .collect(Collectors.toList());
    }

    @Override
    @Cacheable(cacheNames = "addr", key = "'id-'+#id")
    public AddressVo get(Integer id) {
        final Address addr = addressDao.get(id);
        if (addr == null) {
            return null;
        } else return new AddressVo(addr.getId(),
                addr.getOwner(), addr.getContactNumber(),
                Province.descOf(addr.getProvince()), addr.getExactAddr());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AddressVo add(Address addr) {
        redisTemplate.delete("addr::owner-" + addr.getOwner());
        addressDao.add(addr);
        return new AddressVo(addr.getId(),
                addr.getOwner(), addr.getContactNumber(),
                Province.descOf(addr.getProvince()), addr.getExactAddr());
    }

    @Override
    public boolean delete(Integer id) {
        final Integer owner = get(id).getOwner();
        final int rtn = addressDao.delete(id);
        redisTemplate.delete("addr::owner-" + owner);
        redisTemplate.delete("addr::id-" + id);
        return rtn == 1;
    }

    @Override
    public boolean update(AddressUpdateDto info) {
        final Integer id = info.getId();
        final String contactNumber = info.getContactNumber();
        final Integer province = info.getProvince();
        final String exactAddr = info.getExactAddr();
        final Integer owner = get(id).getOwner();
        final int rtn = addressDao.update(id, contactNumber, province, exactAddr);
        redisTemplate.delete("addr::owner-" + owner);
        redisTemplate.delete("addr::id-" + id);
        return rtn == 1;
    }

    @Override
    public String desc(Integer id) {
        final String obj = (String) redisTemplate.opsForValue().get("addr::desc-" + id);
        if (!(obj == null || obj.equals(""))) {
            return obj;
        }
        final AddressVo addressVo = get(id);
        if (addressVo == null) {
            return null;
        }
        final User user = userDao.get(addressVo.getOwner(), null);
        if (user == null) {
            return null;
        }
        final String desc = user.getName() + ": "
                + addressVo.getProvince()
                + addressVo.getExactAddr();
        redisTemplate.opsForValue().set("addr::desc-" + id, desc, 10, TimeUnit.SECONDS);
        return desc;
    }
}
